#include <my_header.h>
#if 0
// 存在两个生产者, 三个消费者
// 生产者每隔3秒生产一个商品, 容器满则等待
// 消费者,在前5秒不消费, 5秒之后, 每隔一秒消费一个商品, 无商品则等待
// 容器初始10个商品, 最大上限20个商品
#endif

/* Usage: ./25_生产者和消费者 */
// 结点结构体

// 定义节点结构体，用于链表  
typedef struct node_s {  
    int value;                // 存储在节点中的整数值  
    struct node_s *p_next;    // 指向链表中下一个节点的指针  
} node_t;  

// 定义队列结构体，使用链表节点实现队列  
typedef struct queue_s {  
    node_t *pHead;           // 指向队列头部的指针（前端）  
    node_t *pEnd;            // 指向队列尾部的指针（后端）  
    int size;                // 队列中的元素数量  
} queue_t;  

// 向队列中添加元素的函数  
void offer(queue_t *pQueue, int value) {  
    node_t *pNewNode = (node_t *)calloc(1, sizeof(node_t)); // 为新节点分配内存  
    pNewNode->value = value; // 设置新节点的值  

    // 如果队列为空，则将头指针和尾指针都指向新节点  
    if (pQueue->size == 0) {  
        pQueue->pHead = pNewNode;  
        pQueue->pEnd = pNewNode;  
    } else { // 如果队列不为空，将新节点添加到尾部并更新尾指针  
        pQueue->pEnd->p_next = pNewNode;  
        pQueue->pEnd = pNewNode;  
    }  
    pQueue->size++; // 增加队列的大小  
}  

// 从队列前端移除并返回元素的函数
int poll(queue_t *pQueue)
{
    // 检查队列是否为空或为NULL
    if(pQueue == NULL || pQueue->size == 0)
    {
        return 0;
    }
    node_t *pOldHead = pQueue->pHead;   // 保存旧头指针
    pQueue->pHead = pOldHead->p_next;   // 更新头指针为下一个节点
    pQueue->size--;

    if(pQueue->size == 0)
    {
        // 如果队列为空，设置尾指针为NULL
        pQueue->pEnd = NULL;    
    }

    int pollValue = pOldHead->value;    // 获取旧头结点的值
    free(pOldHead); // 释放旧头节点的内存
    return pollValue;  // 返回队列前端的值

}

// 打印队列状态的函数
void toString(queue_t *pQueue)
{
    node_t *mid = pQueue->pHead;    // 从头节点开始
    if(mid == NULL)
    {
        return;    // 队列为空，退出
    }
    printf("==  ");
    while(mid)
    {
        printf("%3d ", mid->value); // 打印每个节点的值
        mid = mid->p_next;  // 移动到下一个节点
    }
    printf("==  \n");   // 打印结束标识
}

// 包含队列对象和锁、条件变量的结构体
typedef struct share_value_s{
    queue_t queue;  // 队列
    pthread_mutex_t mLock;
    pthread_cond_t cond;
}share_value_t;

// 生产者线程函数
void *procuce(void *arg)
{
    share_value_t *pShareValue = (share_value_t *)arg;
    while(1)
    {
        // 加锁以保护共享数据
        pthread_mutex_lock(&pShareValue->mLock);
        // 队列满等待
        while(pShareValue->queue.size >= 20)
        {
            pthread_cond_wait(&pShareValue->cond,
                              &pShareValue->mLock);
        }
        int value = rand()% 1000;   // 生成随机值
        offer(&pShareValue->queue, value);  // 将值加入队列 
        printf("add : %d\n", value);    // 打印添加的值
        toString(&pShareValue->queue);  // 打印队列的状态

        pthread_cond_broadcast(&pShareValue->cond); // 通知其他线程
        pthread_mutex_unlock(&pShareValue->mLock);  //解锁
        sleep(3);   // 休眠3秒
    }
    return NULL;
}

// 消费者线程函数
void *consume(void *arg)
{
    // 获取共享数据
    share_value_t *pShareValue = (share_value_t *)arg;

    // 初始休眠5s，等待一些数据被生成
    sleep(5);
    while(1)
    {
        pthread_mutex_lock(&pShareValue->mLock);    // 加锁
        while(pShareValue->queue.size <= 0) //队列为空，等待
        {
            pthread_cond_wait(&pShareValue->cond,
                              &pShareValue->mLock);
        }
        // 从队列取值
        int value = poll(&pShareValue->queue);
        printf("take out :%d\n", value);    // 打印取出的值
        toString(&pShareValue->queue); // 打印出队状态

        pthread_cond_broadcast(&pShareValue->cond); // 通知其他线程
        pthread_mutex_unlock(&pShareValue->mLock); //解锁
        sleep(1);   // 休眠1s
    }
    return NULL;
}

int main(void){              
    // 声明结构体对象
    share_value_t shareValue;
    // 初始化队列
    memset(&shareValue.queue, 0, sizeof(queue_t));
    for(int i =0; i<10; i++)    // 随机生成10个数据
    {   // 在1000之内挑选
        int data = rand()%1000;
        // 将数据加入队列
        offer(&shareValue.queue,data);
    }
    toString(&shareValue.queue);    // 打印队列状态
    pthread_mutex_init(&shareValue.mLock, NULL);
    pthread_cond_init(&shareValue.cond, NULL);

    // 创建子线程(2个生产者和3个消费者)
    pthread_t tid1, tid2, tid3, tid4, tid5;
    int ret_produce1 = pthread_create(&tid1, NULL, procuce, &shareValue);
    THREAD_ERROR_CHECK(ret_produce1, "pthread_create");
    int ret_produce2 = pthread_create(&tid2, NULL, procuce, &shareValue);
    THREAD_ERROR_CHECK(ret_produce2, "pthread_create");
    int ret_consume1 = pthread_create(&tid3, NULL, consume, &shareValue);
    THREAD_ERROR_CHECK(ret_consume1, "pthread_create");
    int ret_consume2 = pthread_create(&tid4, NULL, consume, &shareValue);
    THREAD_ERROR_CHECK(ret_consume2, "pthread_create");
    int ret_consume3 = pthread_create(&tid5, NULL, consume, &shareValue);
    THREAD_ERROR_CHECK(ret_consume3, "pthread_create");

    // 捕获子线程并清理资源
    int ret_join1 = pthread_join(tid1, NULL);
    THREAD_ERROR_CHECK(ret_join1, "pthread_join");
    int ret_join2 = pthread_join(tid2, NULL);
    THREAD_ERROR_CHECK(ret_join2, "pthread_join");
    int ret_join3 = pthread_join(tid3, NULL);
    THREAD_ERROR_CHECK(ret_join3, "pthread_join");
    int ret_join4 = pthread_join(tid4, NULL);
    THREAD_ERROR_CHECK(ret_join4, "pthread_join");
    int ret_join5 = pthread_join(tid5, NULL);
    THREAD_ERROR_CHECK(ret_join5, "pthread_join");

    // 销毁锁和条件变量
    pthread_mutex_destroy(&shareValue.mLock);
    pthread_cond_destroy(&shareValue.cond);
    return 0;
}


